﻿#region Copyright Notice
// 
// 
// Copyright (c) 2009-2010 Anindya Chatterjee
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 
// 
// 
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Reflection;
using System.Serialization.Xml;
using System.Windows.Forms;
using ComponentFactory.Krypton.Toolkit;
using Event.Plugin;
using Event.Plugin.Configuration;
using Microsoft.Win32;

namespace DesktopNotifier.Settings
{
    public partial class ConfigForm : KryptonForm
    {
        private readonly AppConfig _config;
        private readonly EventDescriptor _descriptor;
        private bool _checkAppRestart;

        public ConfigForm(AppConfig config)
        {
            InitializeComponent();
            kryptonWrapLabel1.Text = "Load Events from here.";
            _descriptor = XObjectSerializer<EventDescriptor>.ReadFile(Constants.Descriptor);
            _descriptor.Plugin = _descriptor.Plugin ?? new List<Plugin>();
            _config = config;
        }

        private void addinButton_Click(object sender, EventArgs e)
        {
            var odlg = new OpenFileDialog
                           {
                               Filter = "Event Library | *.dll",
                               Multiselect = true,
                               Title = "Load Events"
                           };
            if (odlg.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    LoadLibraries(odlg.FileNames);
                    kryptonWrapLabel1.Text = "Event Loaded Successfully";
                }
                catch (Exception)
                {
                    kryptonWrapLabel1.Text = "Failed to Load Event. Try again later.";
                }
            }
        }

        /// <summary>
        /// Load a plugin dll from a file name and put an entry to the event descriptor
        /// </summary>
        /// <param name="fileNames"></param>
        private void LoadLibraries(IEnumerable<string> fileNames)
        {
            foreach (string item in fileNames)
            {
                if (item.EndsWith("dll"))
                {
                    try
                    {
                        // copy all dll to the event folder including the reference dlls
                        File.Copy(item, Constants.EventsStore + "\\" +
                                        Path.GetFileName(item), true);

                        // check if the dll contains implementation of AbstractEvents, then add it as an event
                        Assembly assembly = Assembly.LoadFrom(item);
                        foreach (Type type in assembly.GetTypes())
                        {
                            if (type.BaseType == typeof (AbstractEvent))
                            {
                                string name = Path.GetFileNameWithoutExtension(item);
                                _descriptor.Plugin.Add(new Plugin
                                                           {
                                                               Name = name,
                                                               Enable = true
                                                           });
                                if (!eventList.Items.Contains(name))
                                    eventList.SetItemChecked(eventList.Items.Add(name), true);
                                eventList.Refresh();
                            }
                        }
                    }
                    catch (Exception)
                    {
                        continue;
                    }
                }
            }
            _checkAppRestart = true;
        }

        /// <summary>
        /// Loads all the event info from the descriptor to the list box
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ConfigForm_Load(object sender, EventArgs e)
        {
            LoadSettings();
        }

        /// <summary>
        /// Synchronizes descriptor with the list box
        /// </summary>
        private void SaveEvents()
        {
            foreach (Plugin item in _descriptor.Plugin)
            {
                // if event is enabled but not checked
                if (item.Enable && !eventList.CheckedItems.Contains(item.Name))
                {
                    item.Enable = false;
                    _checkAppRestart = true;
                }
                    // if event is disabled but is checked
                else if (!item.Enable && eventList.CheckedItems.Contains(item.Name))
                {
                    item.Enable = true;
                    _checkAppRestart = true;
                }
            }
        }

        private void LoadSettings()
        {
            try
            {
                eventList.Items.Clear();
                int count = 0;
                foreach (Plugin item in _descriptor.Plugin)
                {
                    eventList.Items.Add(item.Name);
                    eventList.SetItemChecked(count, item.Enable);
                    count++;
                }
                eventList.Refresh();

                groupBox.Enabled = proxyCheck.Checked = _config.UseProxy;
                if (_config.Proxy != null)
                {
                    pidTextBox.Text = ((NetworkCredential) _config.Proxy.Credentials).UserName;
                    ppassTextBox.Text = ((NetworkCredential) _config.Proxy.Credentials).Password;

                    phostTextBox.Text = _config.Proxy.Address.Host;
                    pportTextBox.Text = _config.Proxy.Address.Port.ToString();
                }

                RegistryKey ozoneKey =
                    Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
                if (ozoneKey != null && ozoneKey.GetValue("Ozone") != null)
                    windowStartCheckBox.Checked = ((String) ozoneKey.GetValue("Ozone")).Equals(Constants.ExePath);

                updateCheckBox.Checked = _config.AutomaticUpdate;
                kryptonManager.GlobalPaletteMode = _config.Theme;
                themeCombo.SelectedIndex = (int) _config.Theme;
            }
            catch (Exception)
            {
                //TODO: try to load default settings
            }
        }

        private void SaveSettings()
        {
            try
            {
                if (proxyCheck.Checked)
                {
                    _config.UseProxy = proxyCheck.Checked;
                    _config.Proxy = new WebProxy(phostTextBox.Text, Int32.Parse(pportTextBox.Text))
                                        {
                                            Credentials = new NetworkCredential
                                                              {
                                                                  UserName = pidTextBox.Text,
                                                                  Password = ppassTextBox.Text
                                                              }
                                        };
                }
                _config.AutomaticUpdate = updateCheckBox.Checked;
                _config.Theme = kryptonManager.GlobalPaletteMode;
            }
            catch (FormatException)
            {
                MessageBox.Show("Specify the port correctly as a number.");
            }
        }

        private void okButton_Click(object sender, EventArgs e)
        {
            // do all save works before this line
            SaveEvents();
            SaveSettings();
            XObjectSerializer<EventDescriptor>.WriteFile(Constants.Descriptor, _descriptor);
            if (_checkAppRestart && MessageBox.Show(
                                        "Ozone restart is needed for the changes to take effect.\n\tRestart Ozone Now?",
                                        "Event Changes Detected", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) ==
                                    DialogResult.Yes)
            {
                XObjectSerializer<AppConfig>.WriteFile(Constants.Settings, _config, true);
                Application.Restart();
            }
        }

        private void cmdOption_Execute(object sender, EventArgs e)
        {
            int loopCount = 0;
            foreach (AbstractEvent item in EventListener.EventRepository)
            {
                if (item.Name.Equals(eventList.SelectedItem.ToString(),
                                     StringComparison.CurrentCultureIgnoreCase))
                {
                    item.EventSettings.ChangeSettings();
                    loopCount++;
                }
            }
            if (loopCount == 0)
                MessageBox.Show("If you have just enable this event, please restart the app to change settings");
        }

        private void deleteMenuItem_Click(object sender, EventArgs e)
        {
            foreach (Plugin item in _descriptor.Plugin)
            {
                if (item.Name.Equals(eventList.SelectedItem))
                {
                    if (EventListener.RemoveEvent(item.Name))
                    {
                        _descriptor.Plugin.Remove(item);
                        eventList.Items.Remove(eventList.SelectedItem);
                        MessageBox.Show("Event successfully removed");
                        _checkAppRestart = true;
                        eventList.Refresh();
                        break;
                    }
                    MessageBox.Show("Event is failed to remove due to unknown reason.\nTry after some time.");
                }
            }
        }

        private void editMenu_Opening(object sender, CancelEventArgs e)
        {
            if (eventList.SelectedItem == null)
                e.Cancel = true;
            else
                menuHeading.Text = eventList.SelectedItem.ToString();
        }

        private void proxyCheck_CheckedChanged(object sender, EventArgs e)
        {
            groupBox.Enabled = proxyCheck.Checked;
        }

        private void windowStartCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            RegistryKey runKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run",
                                                                 true);

            if (runKey != null)
            {
                if (windowStartCheckBox.Checked)
                {
                    runKey.SetValue("Ozone", Constants.ExePath, RegistryValueKind.String);
                }
                else
                {
                    runKey.SetValue("Ozone", "", RegistryValueKind.String);
                }
                runKey.Close();
            }
        }

        private void themeCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            kryptonManager.GlobalPaletteMode = _config.Theme = (PaletteModeManager) themeCombo.SelectedIndex;
        }
    }
}